
#ifndef __OPENFMS_MODELSIMULATOR_H__
#define __OPENFMS_MODELSIMULATOR_H__

// TODO: Add into faq that stdint.h isn't shipped with MSVC 2008 and before
// Refer to link http://en.wikipedia.org/wiki/Stdint.h
// download to e.g. C:\Program\Microsoft Visual Studio 9.0\VC\include
#include <stdint.h>

#ifdef __cplusplus
#ifdef WIN32
    #include <windows.h>
#else // assume linux
    #include <dlfcn.h>
    #incluce <tchar.h>
#endif
#endif // __cplusplus

/**
 * Structure containing the apparent wind and radio channel data
 */
typedef struct
{
    uint32_t size;     /**< size of struct, must be 92. */
    float linearVelocityX;  /**< X component of apparent velocity through the air [m/s] */
    float linearVelocityY;  /**< Y component of apparent velocity through the air [m/s] */
    float linearVelocityZ;  /**< Z component of apparent velocity through the air [m/s] */
    float angularVelocityX; /**< Component of angular velocity around the x-axis [rad/s] */
    float angularVelocityY; /**< Component of angular velocity around the y-axis [rad/s] */
    float angularVelocityZ; /**< Component of angular velocity around the z-axis [rad/s] */
    float channel[16]; /**< radio channels, each [ -1 ... 0 ... +1 ] */
} ModelSimulator_environment_t;

/**
 * Structure containing mass and inertia properties
 */
typedef struct
{
    uint32_t size; /**< size of struct, must be 20, 24, 28 or 32. */
    float mass;    /**< mass [kg] */
    float ixx;     /**< X-X component of (the symentric) inertia tensor [kg*m2] */
    float iyy;     /**< Y-Y component of (the symentric) inertia tensor [kg*m2] */
    float izz;     /**< Z-Z component of (the symentric) inertia tensor [kg*m2] */
    float ixy;     /**< X-Y component of (the symentric) inertia tensor [kg*m2] */
    float ixz;     /**< X-Z component of (the symentric) inertia tensor [kg*m2] */
    float iyz;     /**< Y-Z component of (the symentric) inertia tensor [kg*m2] */
}  ModelSimulator_inertias_t;

/**
 * Structure holding the force and torque values on an object
 */
typedef struct
{
    uint32_t size;  /**< size of struct in bytes, must be 28 */
    float force_x;  /**< X component of linear forces on c.o.m. [N] */
    float force_y;  /**< Y component of linear forces on c.o.m. [N] */
    float force_z;  /**< Z component of linear forces on c.o.m. [N] */
    float torque_x; /**< Torque on X-axis through c.o.m. [Nm] */
    float torque_y; /**< Torque on Y-axis through c.o.m. [Nm] */
    float torque_z; /**< Torque on Z-axis through c.o.m. [Nm] */

} ModelSimulator_forces_t;

//void addComForces(ModelSimulator_forces_t &com, const ModelSimulator_forces_t &other, float x, float y, float z);
//void setCrossForces(ModelSimulator_forces_t &target, float a_x, float a_y, float a_z, float b_x, float b_y, float b_z);


typedef uint64_t (*ModelSimulator_read_callback_t)( uint64_t, uint64_t, uint64_t ); // num_bytes_read ( custom, buffer_start, buffer_size )
typedef uint64_t ModelSimulator_handle_t;

typedef ModelSimulator_handle_t  (*ModelSimulator_create_t)(ModelSimulator_read_callback_t, uint64_t);  //  handle/0 (,custom)
typedef uint32_t  (*ModelSimulator_destroy_t)(ModelSimulator_handle_t);                  // ret 0 iff ok
typedef uint32_t  (*ModelSimulator_getinertias_t)(ModelSimulator_handle_t, uint64_t );   // ret 0 iff ok (, &inertias struct (from dll) )
typedef uint32_t  (*ModelSimulator_setstepsize_t)(ModelSimulator_handle_t, float);       // ret 0 iff ok (, step_size_in_seconds (to dll) );
typedef uint32_t  (*ModelSimulator_step_t)(ModelSimulator_handle_t, uint64_t, uint64_t); // ret 0 iff ok (, &ModelSimulator_environment (to dll), &ModelSimulator_forces (from dll) )

#ifdef __cplusplus

namespace OpenFms {


/**
 * \class ModelSimulator
 * \brief Wrapper class for a simulator dynamic library.
 *
 * Wparpper for a dynamic library with the following public functions:
 * \c create, \c destroy, \c getinertias, \c setstepsize and \c step.
 */
class ModelSimulator
{
public:
    ModelSimulator();
    ~ModelSimulator();
private:
    void resetAllMembers();
    bool loadFunctions(const TCHAR *pModuleName);

#ifdef WIN32
    HINSTANCE m_hDllFile;                          /**< Handle to dynamic library (Windows). */
#else // assume linux
    void *m_dlfile;                                /**< Handle to dynamic library (Linux). */
#endif
    ModelSimulator_handle_t  m_handle;              /**< Handle to the actual medel */
    ModelSimulator_create_t  m_create_fn;           /**< Pointer to dynamic library \c create function */
    ModelSimulator_destroy_t m_destroy_fn;          /**< Pointer to dynamic library \c destroy funtion */
    ModelSimulator_getinertias_t m_getinertias_fn;  /**< Pointer to dynamic library \c getinerias funtion */
    ModelSimulator_setstepsize_t m_setstepsize_fn;  /**< Pointer to dynamic library \c setstepsize funtion */
    ModelSimulator_step_t m_step_fn;                /**< Pointer to dynamic library \c step funtion */
public:
    bool load(const TCHAR *pModuleName, ModelSimulator_read_callback_t, uint64_t);
    bool load(const TCHAR *pModuleName, const TCHAR *pFileName);

    // Fn mappings to DL
private:
    bool create(ModelSimulator_read_callback_t, uint64_t);
public:
    void destroy();
    bool getInertias(ModelSimulator_inertias_t &);
    bool setStepSize(float);
    bool step(const ModelSimulator_environment_t&, ModelSimulator_forces_t&);


    // ERROR MESSAGE HANDELING
private:
	static const size_t ModelSimulator_ErrorMessage_BufferSize = 200; /**< Size of error message buffer */
    TCHAR m_errorMessage[ModelSimulator_ErrorMessage_BufferSize];     /**< Buffer to store latest error messgae */
    void setErrorMessage(const TCHAR *pMessage);
public:
    const TCHAR *getLastErrorMessage();

};

} // namespace OpenFms
#endif // __cplusplus

#endif // __OPENFMS_MODELSIMULATOR_H__

